Hello, I wanted to change the search box appearance from an ugly grey button to some custom image and I found this task being far from trivial (I even think that there is a bug in Drupal Forms API but I'm a total newbie so I don't want to make quick conclusions). If you have the same issue, read on.

First, please forget the technique which uses CSS only. You may hear of an image replacement trick which substitutes textual 'input type=submit' by some image. Forget it - you will never achieve cross-browser compatibility, I tried hard but failed (I published some results on my Czech blog - you won't understand much but you might appreciate code samples).

The right approach is to change the page rendering and to emit 'input type=image' instead of 'input type=submit'. Here's step-by-step guide:

  1. Navigate to your theme directory and open the template.php file (create it if it doesn't exist).
  2. Add this function:
    function phptemplate_search_theme_form($form) {
      $form['submit']['#theme'] = 'button';
      $form['submit']['#button_type'] = 'image';
      $form['submit']['#attributes'] = array(
        'src' => '/path-to-your-theme/img/search-button.png',
        'alt' => t(Search)
      );
      return form_render($form);
    }
    

    This function changes the search form tree (see the Forms API Quick Start Guide if you don't know what I'm talking about) and then renders the form.

  3. In the perfect world, this would be enough, but currently, you need to hack into the Drupal code because the Forms API doesn't support 'input type=image' directly. So in template.php, create another function with the following content:
    function phptemplate_button($element) {
      // following lines are copied directly from form.inc core file:
    
      //Make sure not to overwrite classes
      if (isset($element['#attributes']['class'])) {
        $element['#attributes']['class'] = 'form-'. $element['#button_type'] .' '. $element['#attributes']['class'];
      }
      else {
        $element['#attributes']['class'] = 'form-'. $element['#button_type'];
      }
    
      // here the novelty begins: check if #button_type is normal submit button or image button
      $return_string = '<input ';
      if ($element['#button_type'] == 'image') {
        $return_string .= 'type="image" ';
      }
      else {
        $return_string .= 'type="submit" ';
      }
      $return_string .= (empty($element['#name']) ? '' : 'name="'. $element['#name'] .'" ') .'value="'. check_plain($element['#value']) .'" '. drupal_attributes($element['#attributes']) ." />\n";;
      return $return_string; 
    }
    
  4. Now, you should be ready to go!

My opinion is that Forms API should be image-input-type aware by default. Note that I'm a total newcomer so I might overlook some simpler way to do this but searching for "image" inside form.inc gives me some self-confidence :)

Hope this helped.

Comments

tag-1’s picture

Very useful. I was about to dig in and do the same but you saved me some time, thanks!

One note -- if you're trying to replace the 'search' button in the side block as I was, you want to implement function phptemplate_search_block_form($form) rather than the function you have in the first block of code above.

jeffrey.dalton’s picture

Implimented this solution and had a custom search button image which seemd like all was well but then found I could no longer post any data for new pages or edit existing pages. When page is submitted nothing happens but the search does work . :-(

Any ideas???

Jeffrey Dalton
Creative Director & Founding Partner
BKJ Digital
https://bkjdigital.com

Mojah’s picture

Better to use a module according to this post...

http://drupal.org/node/140387.

It may be related to the problem you're having and it also may be related to this entire post which goes in the direction of editing the form button via a function at the theming level. The user mooffie states that theming functions are run after forms are processed.

Good luck!

skelly’s picture

Exactly what I wanted to achieve and I was half-way there in a similar fashion till I came across your much neater #button_type work-around.

I agree that this is the "right" way to work around what feels like and oversight in core. Much better than CSS hacks.

Thanks for posting.

HallSL’s picture

Thanks for this. I've almost got it working, but I'm getting two buttons in the code, the new graphic one and the old grey one. FWIW they both work. What am I missing?

I'm doing this to a webform if that makes a difference.

kingandy’s picture

If the form you're altering uses a different name than "submit" for its submit button, then declaring "$form['submit'][...]" will add an element instead of altering the details of the existing one.

Just change 'submit' to whatever your submit button is called. If you're using the name automatically generated by the webform module, this could be something like "submit_NNNNNNNNNN", where NNNNNNNNNN is a timestamp like '1174926303' or similar. IIRC this should be visible on the webform editing page for the form. Failing that you could look at the HTML code for the finished page and find the "name" the original submit button was given.

Hope that helps. Good luck!

++Andy

kingandy’s picture

This works fine in my 5.0 installation after addressing one minor change - form_render has been deprecated (in the sense of 'removed') in favour of drupal_render (as mentioned here: http://drupal.org/node/107459).

So the phptemplate_search_theme_form function I have in my template.php file right now is as follows:

function phptemplate_search_theme_form($form) {
  $form['submit']['#theme'] = 'button';
  $form['submit']['#button_type'] = 'image';
  $form['submit']['#attributes'] = array(
    'src' => base_path() . path_to_theme() . '/images/btn_search.png',
    'alt' => t(Search)
  );
  return drupal_render($form);
}

++Andy

tklawsuc’s picture

When overriding the button function I was no longer able to expand any of the fieldsets of options for a node when in edit mode (at least in 5.x). The issue is that the overridden buttons are missing the id attribute which is required by the drupal/upload javascript files for the upload button (attach-button). Minor addition below (added the id attribute) fixed it.

function phptemplate_button($element) {
  // following lines are copied directly from form.inc core file:

  //Make sure not to overwrite classes
  if (isset($element['#attributes']['class'])) {
    $element['#attributes']['class'] = 'form-'. $element['#button_type'] .' '. $element['#attributes']['class'];
  }
  else {
    $element['#attributes']['class'] = 'form-'. $element['#button_type'];
  }

  // here the novelty begins: check if #button_type is normal submit button or image button
  $return_string = '<input ';
  if ($element['#button_type'] == 'image') {
    $return_string .= 'type="image" ';
  }
  else {
    $return_string .= 'type="submit" ';
  }
  $return_string .= (empty($element['#id']) ? '' : 'id="'. $element['#id'] .'" ');
  $return_string .= (empty($element['#name']) ? '' : 'name="'. $element['#name'] .'" ');
  $return_string .= 'value="'. check_plain($element['#value']) .'" ';
  $return_string .= drupal_attributes($element['#attributes']) ." />\n";
  
  return $return_string;
}

PS Thanks for the original code Borek!

simmerz’s picture

I found the same problem, but resolved it very simply by adding another condition to replace the "submit" as below. This is using drupal 5.1 and fckeditor 2.4. Thanks for the original code though. Lifesaver.

function phptemplate_button($element) {
  // following lines are copied directly from form.inc core file:

  //Make sure not to overwrite classes
  if (isset($element['#attributes']['class'])) {
    $element['#attributes']['class'] = 'form-'. $element['#button_type'] .' '. $element['#attributes']['class'];
  }
  else {
    $element['#attributes']['class'] = 'form-'. $element['#button_type'];
  }

  // My change is type="' . (($element['#button_type'] == "image") ? 'image' : 'submit' ) . '"
  return '<input type="' . (($element['#button_type'] == "image") ? 'image' : 'submit' ) . '" '. (empty($element['#name']) ? '' : 'name="'. $element['#name'] .'" ')  .'id="'. $element['#id'].'" value="'. check_plain($element['#value']) .'" '. drupal_attributes($element['#attributes']) ." />\n";

}
jp.stacey’s picture

Brilliant. Thanks for that: it saved our bacon during a pair-programming session.

Any reason why the core function we're stubbing out doesn't use the .= operator on the classes? Like this:

 function phptemplate_button($element){
  // Make sure not to overwrite classes.
  $element['#attributes']['class'] .= ' form-'. $element['#button_type'];
  
  return '<input type="'.(isset($element['#button_type']) ? $element['#button_type'] : "submit").'" '. (empty($element['#name']) ? '' : 'name="'. $element['#name'] .'" ')  .'id="'. $element['#id'].'" value="'. check_plain($element['#value']) .'" '. drupal_attributes($element['#attributes']) ." />\n";
}   

Also, here's a version of the hook_alter_form to use if you prefer that to intercepting the form at the template level rather than using phptemplate_search_theme_form:

 function mymodule_form_alter($form_id, &$form){
  if ($form_id == 'search_theme_form'){
    $form['submit'] = array(
      '#type' => 'submit',
      '#theme' => 'button',
      '#button_type' => 'image',
      '#value' => t('Go'),
      '#attributes' => array('src' => 'search_go.gif')
    );
  }
}

Expand that if () with else statements for whatever you fancy overriding.

--
J-P Stacey, software gardener, Magnetic Phield

nimzie’s picture

I"ve tried this. To see if I'm getting hooked, I echo some things and it's getting run.

But, my HTML for the search submit btn isn't including the img src bit. I've verified my path to the image.

Is there anything else people can elaborate on which may fix?

Thanks,

Adam

nir’s picture

I tried this code to modify my poll block vote button
the result works in firefox but not in explorer 7

Thanks

asaxe’s picture

I added both of the noted functions to template.php, but I recevie an error message saying the form_render() is undefined. Any thoughts?

Thanks,
Andrew

jaydubb181’s picture

http://drupal.org/node/62647#comment-214956 I got it to work after i changed the function name.

metabits’s picture

Parse error: parse error, unexpected T_VARIABLE in the line

  $form['submit']['#theme'] = 'button';

I tried also with another name instead of 'submit' but the same problem...

Why? (sorry! no idea of PHP but a master on copy-paste ...)

I have Druapl 5.1

psc

kingandy’s picture

Since that line looks OK to me, it's possible the problem really lies on the preceding line - it's not expecting to encounter that variable because it's not done with whatever it was doing before.

Check the end of the line before - did the '{' fall off somehow? (Or, if you've added code, did you miss a ';' ?)

++Andy

metabits’s picture

I copied the two fixes functions for Drupal 5. Yours and tklawsuc's.

The one and only chage I did is the name of the search button image file in my theme images folder.

Is there anything else I should change?

My error message:

Parse error: parse error, unexpected T_VARIABLE in /homepages/24/d32156390/htdocs/drupal5/sites/all/themes/mytheme/template.php on line 31

Line 31 in my template.php is
  $form['enviar']['#theme'] = 'button';

Thanks!

psc

kingandy’s picture

Again, though it's encountering the unexpected variable on line 31 it's likely due to a typo on an earlier line (it's one of those subtly misleading, though wholly accurate, error messages) ... if you post the whole function I'll see if I can spot anything obviously out of place.

++Andy

metabits’s picture

function phptemplate_search_theme_form($form) {
  $form['submit']['#theme'] = 'button';
  $form['submit']['#button_type'] = 'image';
  $form['submit']['#attributes'] = array(
    'src' => base_path() . path_to_theme() . '/images/mysearch.png',
    'alt' => t(Search)
  );
  return drupal_render($form);
}

if i change 'submit' with something different, i get the same error...

should I change something on it (apart form changing my search icon name)?

psc

kenji_kun’s picture

Try : 'alt' => t('Search')

seanr’s picture

Hope you all don;t mind but I found this so incredibly useful that I added it to the snippets library so others would be more readily able to find it and make use of it:

http://drupal.org/node/144758

Sean Robertson
webolutionary@webolutionary.com

hunthunthunt’s picture

This is a great snippet.

Agree, this functionality should be in core.

Thanks also to kingandy's comment.

reed.r’s picture

I did this instead on the output form returned,


$myVariable = str_replace('type="submit"', 'type="image"', str_replace('value="Send"', 'src="files/myimage.gif"', my_form() ) );

much easier, even though I have to admit it is a shortcut and I don't know about the efficiency when there's a lot of users...

SimonVlc’s picture

Anyone achieve to make this work in IE? After pressing the submit image button, it didn´t work in this explorer (it only returns to the same comment page). Any idea? Thanks in advance, Simon.

SimonVlc’s picture

So I must say that this method don´t work in drupal 5.1. At least, for me.

pescobar’s picture

hi simon,

i think i've found out what the issue is in IE

responded in your other thread:

http://drupal.org/node/160682

dgorton’s picture

I wanted to do the same for one of our sites recently and realized the non-trivial size of the task as well. I decided to handle this on the completely other end (via CSS) - but I do wish I'd seen this thread first.

Big picture - both the search text field and the search button needed to be styled. The text field had an odd background (rounded corners and a slight gradient). The search button was a magnifying glass (or some such thing). The following CSS accomplished it in Win IE6, IE7, Firefox 2 and Mac Firefox 2 and Mac Safari 3 (currently in beta). Mac Safari 2 doesn't allow real styling of buttons, but as our site is under development and Safari 3 solves it, we're considering this a sufficient solution (and I like anything that can keep us from fiddling with php - better upgrade paths, etc.)

So - here's the CSS I put together:

#search {
  background-image: url(images/search_background.gif); /* the fancy-looking text input - rounded corners and gradient */
  background-color:transparent;
  background-repeat: no-repeat;
  background-position: left center;
   width: 208px; /* arbitrary - what was necessary for our images to line up */
  text-align: left; /* see above */
}
#search-theme-form div { /* to deal with some IE6 stupidities - relevant because of the way our page lays out and possibly relevant for others */
  margin-right: 0; 
  padding-right: 0;
}
#search #edit-search-theme-form-keys { /* hide the text input box *
  border: none;
  background-color: transparent;
}
#search #edit-submit {  /* hide the search button and put in a fancy little image, instead */ 
  background-color: transparent;  /* hide standard button display stuff */
  border: none;	/* hide standard button display stuff */
  background-image: url(images/search_go_btn.gif); /* put in fancy image */
  background-repeat: no-repeat;
  vertical-align: middle;
  height: 25px; /* fancy image height */
  width: 25px; /* fancy image width */
  text-indent: 25px; /* move the 'Search' text on the button to the right */
  word-spacing: 10em; /* and space it out -- both of these shouldn't be necessary, but the combination makes all our browsers style this correctly */
  text-align: right; /* see above */
  cursor: pointer; /* make the mouse give the right feedback - IE stupidity, again */
}

Took some fiddling to get there, but it works... and it's a pure CSS solution - which means your php can remain untouched.

Drew Gorton
Gorton Studios
Some of our Drupal Sites

asd123asd5’s picture

I personally had problems in opera with the above code, although it worked fine in every other major browser,

however, I am currently using a solution detailed on the below link, and it seems to work for me on every major browser.

http://www.ampsoft.net/webdesign-l/image-button.html

kingandy’s picture

I remember reading an article somewhere that pointed out those methods will make the page unreadable if you have CSS enabled but don't load images for some reason (either a temporary connection glitch or if you just have images disabled as a matter of course - maybe to conserve bandwidth or some such). Since it's not an actual image object you don't get the luxury of 'Alt' text, so if the background image fails to load for whatever reason you'll just get a blank area.

The article did propose some method of addressing it, but I can't remember what. Possibly placing the image in a separate block area, absolutely positioned so as to appear in front of the text? That technique probably wouldn't be applicable for a Submit button anyway.

That said, I use this method all the time for headers. I just thought it was worth mentioning for those of us who care more than me ;)

--Andy
Developing Drupal websites for Livelink New Media

++Andy

asd123asd5’s picture

Hmm, thats a great point. The problem would also effect to text based browsers, and accessibility to the disabled (such as blind). Not sure if a PA fix is really the idea solution. Plus it may become a little complicated if you start moving stuff around with javascript (such as moofx).

If anyone has ideas on a good solution, please enlighten me. I will look into this myself, if I figure anything else i'll post it up here.

Thanks!
Richard Box

dgorton’s picture

Like Andy, I'm both aware of this issue and also aware of my own failings.

FWIW, you can scrutinize that code in it's real life form at http://www.greenguardian.com/. Having a real life test URL may help any effort to throw lots of different user agents at the code and find it's shortcomings.

Suggestions for further improvements are always welcome!

Drew Gorton
Gorton Studios

kingandy’s picture

FWIW, most text-based browsers and/or readers won't be impacted by a text-indent declaration - likewise the normal document flow returns if CSS is lost altogether. It's only people in the bizarre twilight hinterland of active-CSS-but-no-images that will be affected.

--Andy
Developing Drupal websites for Livelink New Media

++Andy

dnewkerk’s picture

In case anyone reads this down the line... I found this solution which works great and solves the above-mentioned accessibility concerns:
http://fortysevenmedia.com/blog/archives/making_accessible_css_buttons_l...

-- David
davidnewkerk.com | absolutecross.com
View my Drupal lessons & guides

kingandy’s picture

Half a year later, I realise that this is what has caused my collapsible fieldsets to conflict with the inline upload functionality. Comparing it with the core theme_button() function, I've realised this code is neglecting to declare an id attribute in the returned input tag. The following code seems to function correctly:

function phptemplate_button($element) {
  // following lines are copied directly from form.inc core file:

  //Make sure not to overwrite classes
  if (isset($element['#attributes']['class'])) {
    $element['#attributes']['class'] = 'form-'. $element['#button_type'] .' '. $element['#attributes']['class'];
  }
  else {
    $element['#attributes']['class'] = 'form-'. $element['#button_type'];
  }

  // here the novelty begins: check if #button_type is normal submit button or image button
  $return_string = '<input ';
  if ($element['#button_type'] == 'image') {
    $return_string .= 'type="image" ';
  }
  else {
    $return_string .= 'type="submit" ';
  }
  $return_string .= (empty($element['#name']) ? '' : 'name="'. $element['#name'] .'" ') .'id="'. $element['#id'].'" value="'. check_plain($element['#value']) .'" '. drupal_attributes($element['#attributes']) ." />\n";
  return $return_string;
}

--Andy
Developing Drupal websites for Livelink New Media

++Andy

dgorton’s picture

This is a great case-in-point where PHP changes can cause something unintended, and a reason to consider spending the time to solve these sorts of visual changes through CSS alone wherever possible. It can still break, mind you (if, for example, the HTML output, such as IDs change) - but that sort of break is both quickly obvious (it's visual) as well as extremely unlikely to effect the functionality of anything else (e.g. only if something else where to be output with ' id="search" ').

Not trying to take away from the hard work and usefulness of the above solutions - just been through this sort of ringer before and unhappy with having to go back and fiddle with phptemplate_* functions when oddities such as this are discovered.

Drew Gorton
Gorton Studios

kingandy’s picture

The other thing that occurred to me while investigating this was that completely overriding the function - ie, duplicating it and making your own changes - means any changes in the core function down the line will not be reflected (which is in fact what's happened here - the 4.7 version of the function doesn't include the id attribute).

Perhaps a better function would be something like:

function phptemplate_button($element) {
  if ($element['#button_type'] == 'image') {

    if (isset($element['#attributes']['class'])) {
      $element['#attributes']['class'] = 'form-'. $element['#button_type'] .' '. $element['#attributes']['class'];
    }
    else {
      $element['#attributes']['class'] = 'form-'. $element['#button_type'];
    }

    return '<input type="image" '. (empty($element['#name']) ? '' : 'name="'. $element['#name'] .'" ')  .'id="'. $element['#id'].'" value="'. check_plain($element['#value']) .'" '. drupal_attributes($element['#attributes']) ." />\n";

  } else {
    return theme_button($element);
  }
}

... Or, heck, even simpler:

 function phptemplate_button($element) {
  $return_value = theme_button($element);
  if ($element['#button_type'] == 'image') {
    $return_value = str_replace('type="submit"','type="image"',$return_value);
  }
  return $return_value;
}

... since literally all we're doing is changing the type from "submit" to "image" (all the SRC attributes and such get passed through regardless of the element type.

On a final note I've noticed this comment above by tklawsuc which both identified and resolved the problem about a week after my first post in this thread. I am dumb.

--Andy
Developing Drupal websites for Livelink New Media

++Andy

Dave Cohen’s picture

Here's a version that looks for images based on the button's #value. This means it will display an image only if the theme has one, but not otherwise (i.e. if 'Submit' was translated to another language).

In this case the theme is called medemcom and images are in themes/medemcom/i/.


/**
 * Replace form submit buttons with images.
 * 
 * Looks for an image file named 'i/b_TITLE.gif', and if found, uses the image.
 */
function medemcom_button(&$element) {
  // Naming convention: images are stored in this theme's i/ directory.
  $filename = 'b_' . strtolower($element['#value']) . '.gif';
  $filepath = drupal_get_path('theme', 'medemcom') . '/i/'.$filename;
  
  if (file_exists($filepath)) {
	// This code based on theme_button from form.inc
	if (isset($element['#attributes']['class'])) {
	  $element['#attributes']['class'] = 'form-'. $element['#button_type'] .' '. $element['#attributes']['class'];
	}
	else {
	  $element['#attributes']['class'] = 'form-'. $element['#button_type'];
	}
	
	$output = '<input type="image" src="'. url($filepath) .'" '. (empty($element['#name']) ? '' : 'name="'. $element['#name'] .'" ')  .'id="'. $element['#id'].'" value="'. check_plain($element['#value']) .'" '. drupal_attributes($element['#attributes']) ." />\n";
  }
  else {
	$output = theme_button($element);
  }
  
  return $output;
}


trevorleenc’s picture

@Dave Cohen

What a great piece of code, while I can see the advantage of using css to do this...was the original direction I was going in, the ability to just create a button say from my own button "dev kit", and then name it like so...drop it in, and forget it...awwww yeah!

thanks!

Dave Cohen’s picture

You know what, unfortunately I started to have problems with that code. Damn IE can't cope with image buttons like normal browsers do. So for example if you make all your Submit buttons images, then on IE you'll have trouble submitting nodes.

If you have any tips to solve that please post here.

dgorton’s picture

Won't it get you there faster and more reliably? The code in the comment above (http://drupal.org/node/62647#comment-258485) works just fine (you can see it in the wild at http://www.greenguardian.com). Variations on that code exist on most of our sites and it works well. Arguably, the CSS above was a bit dense with the layering of background images and all - but a simpler version can be seen, for example, on the Rake Magazine -- http://www.rakemag.com -- just hit the search button with Firebug to take a look:

#searchbox #edit-submit {
  background:transparent url(images/bg-search-button.gif) no-repeat scroll right center;
  border:medium none;
  color:#FFFFFF;
  height:21px;
  padding-left:3px;
  padding-right:20px;
  text-transform:uppercase;
  width:46px;
}

No fussing about with phptemplate functions, no worries with upgrade paths or unintended consequences - that code is only going to effect the search box - and it will do so in a way that degrades extremely well. I have trouble seeing the downside, I guess.

Regardless, however, the good news is that this will be an obsolete conversation come Drupal 6 - I recall reading a changelog somewhere (* I think *) describing image submit buttons in core.

Drew Gorton
Gorton Studios

trevorleenc’s picture

I've got this running on two sites that work well under the following

IE6
IE7
FF2
Opera9
Safari (3.0.4/win)

I have however, not replaced any of drupal's "admin" buttons, but then again, I also use an admin theme anyway.

but I've replaced:
search
advanced search
post comment
preview comment
Log In
Create New Account

and a few others...

what kind of IE issues and where did you encounter them ?

Dave Cohen’s picture

When a button is an image on IE, it neglects to POST the button's value. For many forms this works OK. For the node submit form, Drupal needs to know whether the button pressed was Submit as opposed to Preview or Delete. Since IE never tells the server it was the submit button, nodes can no longer be submitted.

@dgorton: I used code rather than stylesheets because I wanted to very easily support a bunch of different buttons which appear on different forms. In my case the images are pictures of words, and I wanted the proper image to be found on translated pages (and fail gracefully if the translated image was not found).

andrabr’s picture

I just posted one here: http://drupal.org/node/153902#comment-751457

It works for the edit form, but it does require functional jQuery in IE.

trevorleenc’s picture

in order to handle buttons like "Log In" or "Advanced Search" etc, add str_replace() to remove the space in between words.

change this:

$filename = 'b_' . strtolower($element['#value']) . '.gif';

to:

$filename = 'b_' . strtolower(str_replace(" ", "", $element['#value'])) . '.gif';

again...great snipplet!

tordrup’s picture

#mybutton {
background:transparent url(images/mybutton.gif) no-repeat center;
border:none;
cursor:pointer;
font-size:0pt;
color: #ffffff
height:33px; /* or whatever */
width:94px; /* or whatever */
}

This is a presentation-layer problem, so solve it in the presentation layer -- leave your markup and php and modules and API's alone :)

ragaskar’s picture

I think you're right: between these two hacks, the CSS option is the least evil.

FWIW, however, I had better luck with the second technique presented at http://www.ampsoft.net/webdesign-l/image-button.html (the above code failed due to the font-size being set to 0pt):

#edit-submit {
  width:118px;
  height: 25px;
  padding: 25px 0 0;
  margin: 0;
  border: 0;
  background: transparent url(my_button.gif) no-repeat center top;
  overflow: hidden;
  cursor: pointer; /* hand-shaped cursor */
  cursor: hand; /* for IE 5.x */
}
form>#edit-submit { /* For non-IE browsers*/
  height: 0px;
}
BradleyT’s picture

Thanks this one works great.

All I changed was to add the search ID in front of #edit-submit so that my admin forms (and other onsite form submit buttons) didn't change to a little search graphic.

#search #edit-submit {
  width:69px;
  height: 20px;
  padding: 25px 0 0;
  margin: 0;
  border: 0;
  background: transparent url('/themes/pushbutton/images/search.gif') no-repeat center top;
  overflow: hidden;
  cursor: pointer; /* hand-shaped cursor */
  cursor: hand; /* for IE 5.x */
}
#search form>#edit-submit { /* For non-IE browsers*/
  height: 0px;
}
ToshoFreny’s picture

Thanks cooperwd,
I feel this is the best method-- changing the font size to 0px. Other methods mentioned in this page change the padding settings and hide the overflow content, which distorts the placement of the searchbutton in my theme. This one, changing the font-size to 0 is cool, works without distorting my theme alignments.

Loving Life,
Tosho Freny,

JohnnyMoney’s picture

Works great thanks!
*****************************
Drupal Video Tutorials (Spanish)
www.drupalcarmen.com

cookiesunshinex’s picture

coodrup,

Good idea to use font-size: 0; to get rid of the "send" or "submit" text.

Thanks for that.

Dave Cohen’s picture

My earlier approach had the shortcoming that on IE the value of the button was not submitted, and drupal failed to learn the $op of many form submits. (The shortcoming is in IE, not the technique itself). To work around IE's lameness, I'm now using a combination of themeing and javascript. Images are used in place of buttons only when javascript is enabled, and the theme function finds an image for the button in question.

First, the theme function renders both a button and an image. The image is set not to display:

/**
 * Replace form submit buttons with images.
 * 
 * Looks for an image file named 'i/b_TITLE.gif', and if found, uses the image.
 */
function phptemplate_button(&$element) {
  $text = str_replace(' ', '_', $element['#value']);
  // Naming convention: images are stored in this theme's i/ directory.
  $filename = 'b_' . strtolower($text) . '.gif';
  $filepath = drupal_get_path('theme', 'medemcom') . '/i/'.$filename;
  
  // Suppress this behavior on node forms because we dont have images
  // for all buttons
  if (file_exists($filepath)) {
    // Use the original button
	$button = theme_button($element);
	$image = '<input style="display: none;" type="image" src="'. 
	  base_path() . $filepath .'" name="'.$element['#name'] .'" id="'. $element['#id'].'" value="'. check_plain($element['#value']) .'-image" '. drupal_attributes($element['#attributes']) ." />\n";
	// Render the image next to its button equivalent.  Hide the
	// image, it will be shown later only if javascript is enabled.
    $output = '<span class="buttonreplace">'. $button . $image . '</span>';
  }
  else {
	$output = theme_button($element);
  }
  return $output;
}

My theme includes some javascript on every page, and that javascript does two things. First, it hides the buttons and shows the images in their place. Second, when an image is clicked, it triggers the click event on the button. That way its as if the button was pressed, not the image, thus despite the efforts of the developers in Redmond, IE is bent to obey our will:

  /* Buttons are sometimes rendered with their image equivalent, but the image
   is hidden.  If javascript is enabled we can show the image and hide the
   button, then do some work when the click is done to make it work on IE. */
  $('span.buttonreplace input[@type=image]').show().
  click(function (e) {
      // Pass the click on to our button sibing.
      $(this).siblings().click();
      return false;
    });
  $('span.buttonreplace input[@type=submit]').hide().
  click(function (e) {
      // Pass the click on to the browser.
      this.click();
      return true;
    });
bcn’s picture

@Dave
Thanks for this code, it's a big help.
I did notice some strange behavior (in IE of course) on certain forms (specifically the pollfield module), where the form was being submit twice. It seems like the click() function is actually being handled differently on IE vs FF/Safari, so I modified the jQuery:

  $('span.buttonreplace input[@type=image]').show().
  click(function (e) {
    $(this).parents("form").submit();
      return false;
    });
  $('span.buttonreplace input[@type=submit]').hide();

This method might also need a bit of testing to make sure that the direct parent form is being submit, but other than that, I think this should work.

Anyone see any other problems with my changes?

[Update]
Testing indeed... the above bit of jQuery is rubbish. Well, it worked for the pollfield submission form, but seemed to break just about every other form. Needless to say, I would not use it.

[Update Deux]
Ok, I think I've found a solution that works now... Back to Dave's method of emulating the click on the button, with on slight change. I removed (or commented out below) the click() function in the prototype function for the hidden submit button. This second click() was firing a second click event, which broke some forms.

  $('span.buttonreplace input[@type=image]').show().
  click(function (e) {
  // Pass the click on to our button sibing.
    $(this).siblings().click();
    return false;
    });
  $('span.buttonreplace input[@type=submit]').hide().
  click(function (e) {
    // The second click() function was sending a second click event
    //  which broke some forms, so I disabled it, and voila!
    // $(this).click();    
    return true;
    });
Dave Cohen’s picture

Hmmmmm..... I can't recall exactly which browser or what the circumstances were, but I remember needing that this.click() to get a form to submit properly. And it was this.click() (on the DOM object), not $(this).click() (on the jquery object) that I needed.

Maybe we're using different versions of jquery? I've only used that code in Drupal 5.x.

Thanks for the updates, though. It would be good to be certain that code really works everywhere.

bcn’s picture

Ahhh... I think you nailed it, cuz I forgot to mention that I was using a newer version of jquery (1.1.2 from the jquery_update module).

Once again, thanks for posting this in the first place, I now it working on more than 30 or 40 buttons, and can see where this would be very useful for a multi language scenario.

gonz’s picture

gracias.

aterchin’s picture

the php part of this works great, however, the js is doing nothing. It's been added to the theme template, so it's on all the pages.... any ideas?

running drupal 5x, my site's got jquery updated to 1.2.6 I don't know js well, could the problem be that this code is outdated?

robert castelo’s picture

I recommend using this technique instead:

http://alligatorsneeze.com/node/943

Code Positive Limited
Drupal Developers & Consultants - London, UK

------------------------------------------
Drupal Specialists: Consulting, Development & Training

Robert Castelo, CTO
Code Positive
London, United Kingdom
----

aterchin’s picture

robert: thats a great method but unfortunately it doesn't address the problem with IE. just tried it today.

mirian’s picture

Miriam N.
Hi,

The replacement of the button with an image works perfectly to me,

BUT-

I have a submit function to my form and it hasn't been called! just the "form action" was performed..

What did I missed???

thank you,

Miriam

slip’s picture

dsamborschi’s picture

Hi,

It seems to be working except one thing. For some reasons I end up having two buttons, one is the type of image, the second is type of submit.

How to remove the default one and leave just the new image button in the form?

Thanks,
Dan

dsamborschi’s picture

Hi,

It seems to be working except one thing. For some reasons I end up having two buttons, one is the type of image, the second is type of submit.

How to remove the default one and leave just the new image button in the form?

Thanks,
Dan

peterhh’s picture

Hi,

I found a nice easy way was to do it on the form_alter and just use the markup instead:


$form['submit'] = array(
               '#type' => 'markup',
               '#value' => '<input type="image" name="submit" value="enter" src="/'. drupal_get_path('theme', 'myTheme').'/img/submit.jpg" alt="enter">'
             );

rwsimmo’s picture

Thank you for your post peterhh. I can't believe how much time I wasted on this stupid problem.

tsmcreative’s picture

Not sure if this will be the case for everyone, but I found what the core problem was with this issue.

In typical HTML, you can customize a Form Submit Button a few ways. The default would be - type="submit" - followed by the method this thread addresses - type="image" - where you include the source of the image. If you look at the code in - system.module - you'll find where Drupal and developers weren't speaking the same language.

$type['submit'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'));
  $type['button'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => FALSE, '#process' => array('form_expand_ahah'));
  $type['image_button'] = array('#input' => TRUE, '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'),

The third $type variable is where the problem is. For image submit buttons, Drupal was expecting me to set the button type to - "'#type' => 'image_button'" - where I was logically expecting to set the button type to - "'#type' => 'image".

So instead of setting my Image Submit Button Input Type to "image," I used "image-button" and all my problems were gone...well...not ALL...but the ones concerning input type image.

I also added the "name" attribute and value to that particularly problematic line of code. See below.

  $type['image_button'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'),

I hope this helps someone else.

rantebi’s picture

In order to not hack the core you just need to add the button theming as a theme function.

This way:

/**
 * Implementation of hook_theme().
 */
function mymodule_theme(&$existing, $type, $theme, $path) {
  $hooks = zen_theme($existing, $type, $theme, $path);
  $hooks['button'] = array('arguments' => array('element' => NULL),);

  return $hooks;
}

// This allows having an image button
function mymodule_button($element) {
  // following lines are copied directly from form.inc core file:

  //Make sure not to overwrite classes
  if (isset($element['#attributes']['class'])) {
........etc.... etc....
najeem.live’s picture

Hello everybody,

This will solve the issue. I have tried this in Drupal 6.19.

$form['submit_button'] = array(
	      '#type' => 'item',
	      '#name' => 'go',
	      '#id' => 'go',
	      '#title' => '',
	      '#value' => '<input type="image" name="go" src="'.$path.'/images/go.gif" onClick="return Validate(\'alert_name\',\'alert_email\');">'
	    );
drupal5o3’s picture

Hi,

Where would I insert this code? I am using Drupal 6 with the Genesis template.

Thanks,
Ray

Stol’s picture

This is a solution for Drupal 7. In my case it was to set the login button of the user login block to an image. Essential was to set the array value of #theme_wrappers to 'image_button' and to pass the complete $vars array to the render function otherwise you will have two buttons.

function THEME_theme($existing, $type, $theme, $path) {
  return array(
    'user_login_block' => array(
      'render element' => 'form',
    ),
  );
}

function THEME_user_login_block($vars) {
  $vars['form']['actions']['submit']['#theme_wrappers'] = array("image_button");
  $vars['form']['actions']['submit']['#button_type'] = "image";
  $vars['form']['actions']['submit']['#src'] = drupal_get_path('theme', 'THEME_NAME') . '/images/btn-login.png';
  return drupal_render_children($vars);
}

RumpledElf’s picture

function MODULE_search_block_form_alter(&$form, $form_state, $form_id) {
	$form['actions']['submit'] = array('#type' => 'image_button',
		'#value' => t('Search'),
    '#src'  => drupal_get_path('theme','THEME').'/images/searchbutton.png');
}

And another d7 solution.

edgar_estor’s picture

I use css to change the button
first added a div id to identify the button

$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Send'),
'#prefix' => '

',
'#suffix' => '

',
);

then on the css I add the style of the buton

#contact_submit .form-submit{
background:url(images/button-submit.png) no-repeat;
height:34px;
width:129px;
border:none;
text-indent:-9999px;
cursor:pointer;
}

hope this help